{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "fc72d98f-8993-4bd4-a545-23d122f3df71",
      "metadata": {
        "id": "fc72d98f-8993-4bd4-a545-23d122f3df71"
      },
      "source": [
        "# H₂ Molecule Homework Assignment\n",
        "### Quantum Software Development Journey: From Theory to Application with Classiq - Part 3\n",
        "\n",
        "- Similarly to what we have done in class, in this exercise we will implement the VQE on H2 molecule.\n",
        "- This time instead of using the built-in methods and functions (such as `Molecule` and `MoleculeProblem`) to difne and solve the problem, you will be provided with a two qubits Hamiltonian."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "56eda6d8-76c4-4862-b914-0c4598d67274",
      "metadata": {
        "id": "56eda6d8-76c4-4862-b914-0c4598d67274"
      },
      "source": [
        "## Submission\n",
        "- Submit the completed Jupyter notebook and report via GitHub. Ensure all files are correctly named and organized.\n",
        "- Use the Typeform link provided in the submission folder to confirm your submission.\n",
        "\n",
        "## Additional Resources\n",
        "- [Classiq Documentation](https://docs.classiq.io/latest/)\n",
        "- The notebook from live session #3\n",
        "\n",
        "## Important Dates\n",
        "- **Assignment Release:** 22.5.2024\n",
        "- **Submission Deadline:** 3.6.2024 (7 A.M GMT+3)\n",
        "\n",
        "---\n",
        "\n",
        "Happy coding and good luck!"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d41e969d-f6a7-4ff7-9660-19ce6c97ba6b",
      "metadata": {
        "id": "d41e969d-f6a7-4ff7-9660-19ce6c97ba6b"
      },
      "source": [
        "### Part 1"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f710d6f4-d40b-42d5-b524-c6acb8059fe2",
      "metadata": {
        "id": "f710d6f4-d40b-42d5-b524-c6acb8059fe2"
      },
      "source": [
        "Given the following Hamiltonian:"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6ba8a6f1-3259-4492-a1ca-3abde7530cd4",
      "metadata": {
        "id": "6ba8a6f1-3259-4492-a1ca-3abde7530cd4"
      },
      "source": [
        "$$\n",
        "\\hat{H} = -1.0523 \\cdot (I \\otimes I) + 0.3979 \\cdot (I \\otimes Z) - 0.3979 \\cdot (Z \\otimes I) - 0.0112 \\cdot (Z \\otimes Z) + 0.1809 \\cdot (X \\otimes X)\n",
        "$$"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "736d275c-9a5a-4c08-b891-3078430dc6c1",
      "metadata": {
        "id": "736d275c-9a5a-4c08-b891-3078430dc6c1"
      },
      "source": [
        "Complete the following code"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install -U -q classiq"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "collapsed": true,
        "id": "imjx_MjrLbGs",
        "outputId": "41671177-4fd4-4eef-d299-b5edab53a274"
      },
      "id": "imjx_MjrLbGs",
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m398.1/398.1 kB\u001b[0m \u001b[31m3.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m10.7/10.7 MB\u001b[0m \u001b[31m25.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m33.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.6/75.6 kB\u001b[0m \u001b[31m4.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m26.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m42.6/42.6 kB\u001b[0m \u001b[31m2.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.1/3.1 MB\u001b[0m \u001b[31m41.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m6.4/6.4 MB\u001b[0m \u001b[31m41.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m77.9/77.9 kB\u001b[0m \u001b[31m4.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m4.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.6/49.6 kB\u001b[0m \u001b[31m5.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
            "torch 2.3.0+cu121 requires nvidia-cublas-cu12==12.1.3.1; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-cuda-cupti-cu12==12.1.105; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-cuda-nvrtc-cu12==12.1.105; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-cuda-runtime-cu12==12.1.105; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-cudnn-cu12==8.9.2.26; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-cufft-cu12==11.0.2.54; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-curand-cu12==10.3.2.106; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-cusolver-cu12==11.4.5.107; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-cusparse-cu12==12.1.0.106; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-nccl-cu12==2.20.5; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\n",
            "torch 2.3.0+cu121 requires nvidia-nvtx-cu12==12.1.105; platform_system == \"Linux\" and platform_machine == \"x86_64\", which is not installed.\u001b[0m\u001b[31m\n",
            "\u001b[0m"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "import classiq\n",
        "classiq.authenticate()"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "UjUn859jLcaS",
        "outputId": "1d9eb96e-fefe-42c3-c71d-cd24bfb5d4cb"
      },
      "id": "UjUn859jLcaS",
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Your user code: JPTW-QDSJ\n",
            "If a browser doesn't automatically open, please visit this URL from any trusted device: https://auth.classiq.io/activate?user_code=JPTW-QDSJ\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "19266c11-6acc-4edb-910f-2d0dfe80a6c8",
      "metadata": {
        "id": "19266c11-6acc-4edb-910f-2d0dfe80a6c8"
      },
      "outputs": [],
      "source": [
        "from typing import List\n",
        "from classiq import *\n",
        "\n",
        "HAMILTONIAN = QConstant(\"HAMILTONIAN\", List[PauliTerm],\n",
        "                        [PauliTerm([Pauli.I, Pauli.I], -1.0523),\n",
        "                        PauliTerm([Pauli.I,Pauli.Z], 0.3979),\n",
        "                        PauliTerm([Pauli.Z,Pauli.I], -0.3979),\n",
        "                        PauliTerm([Pauli.Z,Pauli.Z], -0.0112),\n",
        "                        PauliTerm([Pauli.X, Pauli.X], 0.1809)])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "0bb68899-2076-45c0-8868-131f38aa3b78",
      "metadata": {
        "id": "0bb68899-2076-45c0-8868-131f38aa3b78"
      },
      "outputs": [],
      "source": [
        "@qfunc\n",
        "def main(q: Output[QArray[QBit]], angles: CArray[CReal, 3]) -> None:\n",
        "    # Create an ansatz which allows each qubit to have arbitrary rotation\n",
        "    allocate(2, q)\n",
        "    U(angles[0], angles[1], angles[2], 0, q[0])\n",
        "    U(angles[0], angles[1], angles[2], 0, q[1])\n",
        "\n",
        "\n",
        "@cfunc\n",
        "def cmain() -> None:\n",
        "    res = vqe(\n",
        "        HAMILTONIAN,\n",
        "        False,\n",
        "        [],\n",
        "        optimizer=Optimizer.COBYLA,\n",
        "        max_iteration=1000,\n",
        "        tolerance=0.001,\n",
        "        step_size=0,\n",
        "        skip_compute_variance=False,\n",
        "        alpha_cvar=1.0,\n",
        "    )\n",
        "    save({\"result\": res})\n",
        "\n",
        "qmod = create_model(main, classical_execution_function=cmain)\n",
        "qprog = synthesize(qmod)\n",
        "# show(qprog)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "0563c1a8-7aec-4da9-9105-6b16c5c24382",
      "metadata": {
        "id": "0563c1a8-7aec-4da9-9105-6b16c5c24382"
      },
      "outputs": [],
      "source": [
        "execution = execute(qprog)\n",
        "res = execution.result()\n",
        "# execution.open_in_ide()\n",
        "\n",
        "vqe_result = res[0].value"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "de17cfc0-8e64-4493-b4c2-4a97fc9797a0",
      "metadata": {
        "scrolled": true,
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "de17cfc0-8e64-4493-b4c2-4a97fc9797a0",
        "outputId": "695489b1-dcff-431b-8f8a-b90daaa26ff5"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Optimal energy: -1.06546357421875\n",
            "Optimal parameters: {'angles_0': 6.139678585190387, 'angles_1': 4.976498216901541, 'angles_2': -4.571133358645985}\n",
            "Eigenstate: {'01': (0.06629126073623882+0j), '10': (0.07328774624724109+0j), '00': (0.9951052080056662+0j)}\n"
          ]
        }
      ],
      "source": [
        "print(f\"Optimal energy: {vqe_result.energy}\")\n",
        "print(f\"Optimal parameters: {vqe_result.optimal_parameters}\")\n",
        "print(f\"Eigenstate: {vqe_result.eigenstate}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5df11dfc-3e3a-4191-bd47-d522ca3dcbfa",
      "metadata": {
        "id": "5df11dfc-3e3a-4191-bd47-d522ca3dcbfa"
      },
      "source": [
        "Does it similar to the `optimal energy` we calculated in class? \\\n",
        "Does it similar to the `total energy` we calculated in class?"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4f0e0bea-b12f-43ad-94e8-100fedf2b57f",
      "metadata": {
        "id": "4f0e0bea-b12f-43ad-94e8-100fedf2b57f"
      },
      "source": [
        "### Part 2"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "66882248-de08-4a6e-b33c-647f015f7d79",
      "metadata": {
        "id": "66882248-de08-4a6e-b33c-647f015f7d79"
      },
      "source": [
        "**Now, we want to have a more interesting ansatz in our `main`.**  \n",
        "Add **one** line of code to the `main` function you created in Part 1 that creates **entanglement** between the two qubits.  \n",
        "Which gate should you use?"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "bb39be9e-4994-44e5-84d8-c99bc8b77145",
      "metadata": {
        "id": "bb39be9e-4994-44e5-84d8-c99bc8b77145"
      },
      "outputs": [],
      "source": [
        "from typing import List\n",
        "from classiq import *\n",
        "\n",
        "\n",
        "@qfunc\n",
        "def main(q: Output[QArray[QBit]], angles: CArray[CReal, 3]) -> None:\n",
        "    # TODO: Create an ansatz which allows each qubit to have arbitrary rotation\n",
        "    allocate(2, q)\n",
        "    U(angles[0], angles[1], angles[2], 0, q[0])\n",
        "    U(angles[0], angles[1], angles[2], 0, q[1])\n",
        "    CX(q[0], q[1])\n",
        "\n",
        "\n",
        "\n",
        "@cfunc\n",
        "def cmain() -> None:\n",
        "    res = vqe(\n",
        "        HAMILTONIAN, # TODO: complete the missing argument\n",
        "        False,\n",
        "        [],\n",
        "        optimizer=Optimizer.COBYLA,\n",
        "        max_iteration=1000,\n",
        "        tolerance=0.001,\n",
        "        step_size=0,\n",
        "        skip_compute_variance=False,\n",
        "        alpha_cvar=1.0,\n",
        "    )\n",
        "    save({\"result\": res})\n",
        "\n",
        "qmod = create_model(main, classical_execution_function=cmain)\n",
        "qprog = synthesize(qmod)\n",
        "# show(qprog)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "112a1590-283c-4f79-8035-72936561102d",
      "metadata": {
        "id": "112a1590-283c-4f79-8035-72936561102d"
      },
      "outputs": [],
      "source": [
        "execution = execute(qprog)\n",
        "res = execution.result()\n",
        "# execution.open_in_ide()\n",
        "vqe_result = res[0].value"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "06500e4c-a04b-4cfa-a84d-41f96a0c68eb",
      "metadata": {
        "collapsed": true,
        "jupyter": {
          "outputs_hidden": true
        },
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "06500e4c-a04b-4cfa-a84d-41f96a0c68eb",
        "outputId": "32d0ab57-094e-495d-fe1e-6be7c916b9d8"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Optimal energy: -1.8593486328125\n",
            "Optimal parameters: {'angles_0': -3.344661707239267, 'angles_1': 2.9341114783374493, 'angles_2': -2.868211044897404}\n",
            "Eigenstate: {'11': (0.10126157341262282+0j), '10': (0.11481983169296148+0j), '01': (0.9882117688026185+0j)}\n"
          ]
        }
      ],
      "source": [
        "print(f\"Optimal energy: {vqe_result.energy}\")\n",
        "print(f\"Optimal parameters: {vqe_result.optimal_parameters}\")\n",
        "print(f\"Eigenstate: {vqe_result.eigenstate}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "30a635d7-2f15-4c94-a94b-f4270f17aed8",
      "metadata": {
        "id": "30a635d7-2f15-4c94-a94b-f4270f17aed8"
      },
      "source": [
        "Does it similar to the `optimal energy` we calculated in class? \\\n",
        "Does it similar to the `total energy` we calculated in class? \\\n",
        "What can we learn about the provided  form this result Hamiltonian?"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.16"
    },
    "colab": {
      "provenance": []
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}